package org.apache.dolphinscheduler.api.controller;

import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.dolphinscheduler.api.aspect.AccessLogAnnotation;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.exceptions.ApiException;
import org.apache.dolphinscheduler.api.service.ModelService;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.Constants;
import org.apache.dolphinscheduler.common.utils.HadoopUtils;
import org.apache.dolphinscheduler.dao.entity.Model;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.spi.enums.ResourceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import java.io.ByteArrayOutputStream;
import java.util.Date;
import java.util.Map;

import static org.apache.dolphinscheduler.api.enums.Status.*;

@RestController
@RequestMapping("/model")
public class ModelController extends BaseController{

    private static final Logger logger = LoggerFactory.getLogger(ModelController.class);

    @Autowired
    private ModelService modelService;

    /**
     * 保存模型
     * @param modelName
     * @param alias
     * @param describe
     * @param nodeId
     * @param userId
     * @return
     */
    @PostMapping(value = "/insertModel")
    @ResponseStatus(HttpStatus.OK)
    public Object insertModel(
                              @RequestParam(value = "modelName") String modelName,
                              @RequestParam(value = "alias") String alias,
                              @RequestParam(value = "describe") String describe,
                              @RequestParam(value = "nodeId") Integer nodeId,
                              @RequestParam(value = "userId") Integer userId
                              ){
        Model model=new Model();
        model.setModelName(modelName);
        //model.setNodeId(nodeId);
        model.setAlias(modelName);
        model.setDescribe(describe);
        model.setNodeId(nodeId);
        model.setUserId(userId);
        Map<String, Object> result =modelService.insertModel(model);
        return returnDataList(result);
    }

    /**
     * 模型分页显示
     * @param userId
     * @param pageSize
     * @param currentPage
     * @param searchVal
     * @return
     */
    @GetMapping(value = "/viewModel")
    @ResponseStatus(HttpStatus.OK)
    public Result viewModel(
            @RequestParam(value = "userId") Integer userId,
            @RequestParam(value = "pageSize") Integer pageSize,
            @RequestParam(value = "currentPage") Integer currentPage,
            @RequestParam(value = "searchVal") String searchVal
    ){
        Result result = new Result();
        result = modelService.queryModelListPaging(userId,pageSize,currentPage,searchVal);
        return result;
    }

    /**
     * 模型分页显示
     * @param userId
     * @param
     * @return
     */
    @GetMapping(value = "/viewModelMenu")
    @ResponseStatus(HttpStatus.OK)
    public Map<String, Object> viewModelMenu(
            @RequestParam(value = "userId") Integer userId
    ){
        Map<String, Object> result = modelService.viewModel(userId);
        return result;
    }

    /**
     * 删除
     * @param id
     * @return
     */
    @DeleteMapping(value = "/deleteModel")
    @ResponseStatus(HttpStatus.OK)
    public Object deleteModel(
            @RequestParam(value = "id") Integer id
    ){
        Map<String, Object> result =modelService.deleteModelById(id);
        return returnDataList(result);
    }

    /**
     * 上传模型
     * @param loginUser
     * @param type
     * @param alias
     * @param description
     * @param file
     * @return
     */
    @PostMapping("/upFile")
    @ApiException(CREATE_RESOURCE_ERROR)
    @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
    public Object createResource(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                 @RequestParam(value = "type") ResourceType type,
                                 @RequestParam(value = "alias", required = false) String alias,
                                 @RequestParam(value = "description", required = false) String description,
                                 @RequestParam("file") MultipartFile file) {
        Map<String, Object> result =modelService.uploadModel(loginUser,alias,description,file,type);
        return result;
    }

    /**
     * 下载模型
     * @param modelId
     * @return
     * @throws Exception
     */
    @GetMapping(value = "/download")
    @ResponseBody
    @ApiException(DOWNLOAD_RESOURCE_FILE_ERROR)
    @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
    public ResponseEntity downloadResource(
                                           @PathVariable(value = "id") int modelId) throws Exception {
        ResponseEntity response = null;
        String hdfsPath=modelService.getHdfsFilename(modelId);
        HttpHeaders headers = new HttpHeaders();
        headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
        headers.add("Content-Disposition", "attachment; filename=" + System.currentTimeMillis() + ".zip");
        headers.add("Pragma", "no-cache");
        headers.add("Expires", "0");
        headers.add("Last-Modified", new Date().toString());
        headers.add("ETag", String.valueOf(System.currentTimeMillis()));
        try {
            ByteArrayOutputStream zos = (ByteArrayOutputStream) HadoopUtils.downDir(hdfsPath);
            byte[] out = zos.toByteArray();
            zos.close();
            response = new ResponseEntity<>(out, headers, HttpStatus.OK);
        }catch (Exception e){
            logger.error("下载资源出错:"+e,e.getMessage());
        }
        return response;
    }

    /**
     * verify resource by alias and type
     *
     * @param loginUser login user
     * @param
     * @param type resource type
     * @return true if the resource name not exists, otherwise return false
     */
    @ApiOperation(value = "verifyResourceName", notes = "VERIFY_RESOURCE_NAME_NOTES")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "type", value = "RESOURCE_TYPE", required = true, dataType = "ResourceType"),
            @ApiImplicitParam(name = "fullName", value = "RESOURCE_FULL_NAME", required = true, dataType = "String")
    })

    @GetMapping(value = "/verify-name")
    @ResponseStatus(HttpStatus.OK)
    @ApiException(VERIFY_RESOURCE_BY_NAME_AND_TYPE_ERROR)
    @AccessLogAnnotation(ignoreRequestArgs = "loginUser")
    public Result verifyResourceName(@ApiIgnore @RequestAttribute(value = Constants.SESSION_USER) User loginUser,
                                     @RequestParam(value = "alias") String alias,
                                     @RequestParam(value = "type") ResourceType type
    ) {
        return modelService.verifyModelName(alias, type, loginUser);
    }

}
